package com.dux.commons.concurrent.stats;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.commons.lang.ArrayUtils;
import org.apache.log4j.Logger;

/**
 * 执行方法统计管理
 * @author 杜祥
 * @create 2013-9-9
 */
public class RunnableStatsManager
{
	private static final Logger log = Logger.getLogger(RunnableStatsManager.class);
	
	private static final Map<Class<?>, ClassStat> classStats = new HashMap<Class<?>, RunnableStatsManager.ClassStat>();
	
	
	/**
	 * 类统计
	 * @author 杜祥
	 * @create 2013-9-9
	 */
	private static final class ClassStat
	{
		private final String className;
		
		private final MethodStat runnableStat;
		
		private String[] methodNames;
		private MethodStat[] methodStats;
		
		private ClassStat(Class<?> clazz)
		{
			className = clazz.getName();
			
			runnableStat = new MethodStat(className, "run");
			
			methodNames = new String[] {"run()"};
			
			methodStats = new MethodStat[] {runnableStat};
		}
		
		
		private MethodStat getRunnableStat()
		{
			return runnableStat;
		}
		
		
		private MethodStat getMethodStat(String methodName, boolean synchronizedAlready)
		{
			if ("run()".equals(methodName))
				return runnableStat;

			for (int i = 0; i < methodNames.length; i++)
				if (methodNames[i].equals(methodName))
					return methodStats[i];

			if (!synchronizedAlready) {
				synchronized (this) {
					return getMethodStat(methodName, true);
				}
			}

			methodName = methodName.intern();

			final MethodStat methodStat = new MethodStat(className, methodName);

			methodNames = (String[]) ArrayUtils.add(methodNames, methodName);
			methodStats = (MethodStat[]) ArrayUtils.add(methodStats, methodStat);

			return methodStat;
		}
		
	}

	
	/**
	 * 方法统计
	 * @author 杜祥
	 * @create 2013-9-9
	 */
	private static final class MethodStat
	{
		private final ReentrantLock lock = new ReentrantLock();
		
		private final String className;
		
		private final String methodName;
		
		/**
		 * 执行次数
		 */
		private long count;
		
		/**
		 * 总时间
		 */
		private long total;
		
		private long min = Long.MAX_VALUE;
		
		private long max = Long.MIN_VALUE;
		
		private MethodStat(String className, String methodName)
		{
			this.className = className;
			
			this.methodName = methodName;
		}
		
		
		private void handleStats(long runTime)
		{
			lock.lock();
			try 
			{
				count++;
				total += runTime;
				min = Math.min(min, runTime);
				max = Math.max(max, runTime);
			} 
			finally
			{
				lock.unlock();
			}
		}
		
	}
	
	
	/**
	 * 获得指定类的类统计信息
	 * @param clazz							类
	 * @param synchronizedAlready			是否同步
	 * @return
	 */
	private static ClassStat getClassStat(Class<?> clazz, boolean synchronizedAlready) 
	{
		ClassStat classStat = classStats.get(clazz);

		if (classStat != null)
			return classStat;

		if (!synchronizedAlready) 
		{
			synchronized (RunnableStatsManager.class) 
			{
				return getClassStat(clazz, true);
			}
		}
		return new ClassStat(clazz);
	}
	
	
	public static void handleStats(Class<? extends Runnable> clazz, long runTime)
	{
		getClassStat(clazz, false).getRunnableStat().handleStats(runTime);
	}

	
	public static void handleStats(Class<?> clazz, String methodName, long runTime) 
	{
		getClassStat(clazz, false).getMethodStat(methodName, false).handleStats(runTime);
	}
	
}
